/*                                                                                                                                                                                                                                                                           
 * Licensed to the Apache Software Foundation (ASF) under one or more                                                                                                                                                                                                        
 * contributor license agreements.  See the NOTICE file distributed with                                                                                                                                                                                                     
 * this work for additional information regarding copyright ownership.                                                                                                                                                                                                       
 * The ASF licenses this file to You under the Apache License, Version 2.0                                                                                                                                                                                                   
 * (the "License"); you may not use this file except in compliance with                                                                                                                                                                                                      
 * the License.  You may obtain a copy of the License at                                                                                                                                                                                                                     
 *                                                                                                                                                                                                                                                                           
 *      http://www.apache.org/licenses/LICENSE-2.0                                                                                                                                                                                                                           
 *                                                                                                                                                                                                                                                                           
 * Unless required by applicable law or agreed to in writing, software                                                                                                                                                                                                       
 * distributed under the License is distributed on an "AS IS" BASIS,                                                                                                                                                                                                         
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                                                                                                                                                                                  
 * See the License for the specific language governing permissions and                                                                                                                                                                                                       
 * limitations under the License.                                                                                                                                                                                                                                            
 */                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                             
package org.apache.commons.net;                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                             
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
                                                                                                                                                                                                                                                                             
/***                                                                                                                                                                                                                                                                         
 * The DatagramSocketClient provides the basic operations that are required                                                                                                                                                                                                  
 * of client objects accessing datagram sockets.  It is meant to be                                                                                                                                                                                                          
 * subclassed to avoid having to rewrite the same code over and over again                                                                                                                                                                                                   
 * to open a socket, close a socket, set timeouts, etc.  Of special note                                                                                                                                                                                                     
 * is the {@link #setDatagramSocketFactory  setDatagramSocketFactory }                                                                                                                                                                                                       
 * method, which allows you to control the type of DatagramSocket the                                                                                                                                                                                                        
 * DatagramSocketClient creates for network communications.  This is                                                                                                                                                                                                         
 * especially useful for adding things like proxy support as well as better                                                                                                                                                                                                  
 * support for applets.  For                                                                                                                                                                                                                                                 
 * example, you could create a                                                                                                                                                                                                                                               
 * {@link org.apache.commons.net.DatagramSocketFactory}                                                                                                                                                                                                                      
 *  that                                                                                                                                                                                                                                                                     
 * requests browser security capabilities before creating a socket.                                                                                                                                                                                                          
 * All classes derived from DatagramSocketClient should use the                                                                                                                                                                                                              
 * {@link #_socketFactory_  _socketFactory_ } member variable to                                                                                                                                                                                                             
 * create DatagramSocket instances rather than instantiating                                                                                                                                                                                                                 
 * them by directly invoking a constructor.  By honoring this contract                                                                                                                                                                                                       
 * you guarantee that a user will always be able to provide his own                                                                                                                                                                                                          
 * Socket implementations by substituting his own SocketFactory.                                                                                                                                                                                                             
 * <p>                                                                                                                                                                                                                                                                       
 * <p>                                                                                                                                                                                                                                                                       
 * @see DatagramSocketFactory                                                                                                                                                                                                                                                
 ***/                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
public abstract class DatagramSocketClient                                                                                                                                                                                                                                   
{                                                                                                                                                                                                                                                                            
    /***                                                                                                                                                                                                                                                                     
     * The default DatagramSocketFactory shared by all DatagramSocketClient                                                                                                                                                                                                  
     * instances.                                                                                                                                                                                                                                                            
     ***/                                                                                                                                                                                                                                                                    
    private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY =                                                                                                                                                                                                    
        new DefaultDatagramSocketFactory();                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                             
    /*** The timeout to use after opening a socket. ***/                                                                                                                                                                                                                     
    protected int _timeout_;                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                             
    /*** The datagram socket used for the connection. ***/                                                                                                                                                                                                                   
    protected DatagramSocket _socket_;                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * A status variable indicating if the client's socket is currently open.                                                                                                                                                                                                
     ***/                                                                                                                                                                                                                                                                    
    protected boolean _isOpen_;                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                             
    /*** The datagram socket's DatagramSocketFactory. ***/                                                                                                                                                                                                                   
    protected DatagramSocketFactory _socketFactory_;                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Default constructor for DatagramSocketClient.  Initializes                                                                                                                                                                                                            
     * _socket_ to null, _timeout_ to 0, and _isOpen_ to false.                                                                                                                                                                                                              
     ***/                                                                                                                                                                                                                                                                    
    public DatagramSocketClient()                                                                                                                                                                                                                                            
    {                                                                                                                                                                                                                                                                        
        _socket_ = null;                                                                                                                                                                                                                                                     
        _timeout_ = 0;                                                                                                                                                                                                                                                       
        _isOpen_ = false;                                                                                                                                                                                                                                                    
        _socketFactory_ = __DEFAULT_SOCKET_FACTORY;                                                                                                                                                                                                                          
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Opens a DatagramSocket on the local host at the first available port.                                                                                                                                                                                                 
     * Also sets the timeout on the socket to the default timeout set                                                                                                                                                                                                        
     * by {@link #setDefaultTimeout  setDefaultTimeout() }.                                                                                                                                                                                                                  
     * <p>                                                                                                                                                                                                                                                                   
     * _isOpen_ is set to true after calling this method and _socket_                                                                                                                                                                                                        
     * is set to the newly opened socket.                                                                                                                                                                                                                                    
     * <p>                                                                                                                                                                                                                                                                   
     * @exception SocketException If the socket could not be opened or the                                                                                                                                                                                                   
     *   timeout could not be set.                                                                                                                                                                                                                                           
     ***/                                                                                                                                                                                                                                                                    
    public void open() throws SocketException                                                                                                                                                                                                                                
    {                                                                                                                                                                                                                                                                        
        _socket_ = _socketFactory_.createDatagramSocket();                                                                                                                                                                                                                   
        _socket_.setSoTimeout(_timeout_);                                                                                                                                                                                                                                    
        _isOpen_ = true;                                                                                                                                                                                                                                                     
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Opens a DatagramSocket on the local host at a specified port.                                                                                                                                                                                                         
     * Also sets the timeout on the socket to the default timeout set                                                                                                                                                                                                        
     * by {@link #setDefaultTimeout  setDefaultTimeout() }.                                                                                                                                                                                                                  
     * <p>                                                                                                                                                                                                                                                                   
     * _isOpen_ is set to true after calling this method and _socket_                                                                                                                                                                                                        
     * is set to the newly opened socket.                                                                                                                                                                                                                                    
     * <p>                                                                                                                                                                                                                                                                   
     * @param port The port to use for the socket.                                                                                                                                                                                                                           
     * @exception SocketException If the socket could not be opened or the                                                                                                                                                                                                   
     *   timeout could not be set.                                                                                                                                                                                                                                           
     ***/                                                                                                                                                                                                                                                                    
    public void open(int port) throws SocketException                                                                                                                                                                                                                        
    {                                                                                                                                                                                                                                                                        
        _socket_ = _socketFactory_.createDatagramSocket(port);                                                                                                                                                                                                               
        _socket_.setSoTimeout(_timeout_);                                                                                                                                                                                                                                    
        _isOpen_ = true;                                                                                                                                                                                                                                                     
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Opens a DatagramSocket at the specified address on the local host                                                                                                                                                                                                     
     * at a specified port.                                                                                                                                                                                                                                                  
     * Also sets the timeout on the socket to the default timeout set                                                                                                                                                                                                        
     * by {@link #setDefaultTimeout  setDefaultTimeout() }.                                                                                                                                                                                                                  
     * <p>                                                                                                                                                                                                                                                                   
     * _isOpen_ is set to true after calling this method and _socket_                                                                                                                                                                                                        
     * is set to the newly opened socket.                                                                                                                                                                                                                                    
     * <p>                                                                                                                                                                                                                                                                   
     * @param port The port to use for the socket.                                                                                                                                                                                                                           
     * @param laddr  The local address to use.                                                                                                                                                                                                                               
     * @exception SocketException If the socket could not be opened or the                                                                                                                                                                                                   
     *   timeout could not be set.                                                                                                                                                                                                                                           
     ***/                                                                                                                                                                                                                                                                    
    public void open(int port, InetAddress laddr) throws SocketException                                                                                                                                                                                                     
    {                                                                                                                                                                                                                                                                        
        _socket_ = _socketFactory_.createDatagramSocket(port, laddr);                                                                                                                                                                                                        
        _socket_.setSoTimeout(_timeout_);                                                                                                                                                                                                                                    
        _isOpen_ = true;                                                                                                                                                                                                                                                     
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Closes the DatagramSocket used for the connection.                                                                                                                                                                                                                    
     * You should call this method after you've finished using the class                                                                                                                                                                                                     
     * instance and also before you call {@link #open open() }                                                                                                                                                                                                               
     * again.   _isOpen_ is set to false and  _socket_ is set to null.                                                                                                                                                                                                       
     * If you call this method when the client socket is not open,                                                                                                                                                                                                           
     * a NullPointerException is thrown.                                                                                                                                                                                                                                     
     ***/                                                                                                                                                                                                                                                                    
    public void close()                                                                                                                                                                                                                                                      
    {                                                                                                                                                                                                                                                                        
        if (_socket_ != null) {                                                                                                                                                                                                                                              
            _socket_.close();                                                                                                                                                                                                                                                
        }                                                                                                                                                                                                                                                                    
        _socket_ = null;                                                                                                                                                                                                                                                     
        _isOpen_ = false;                                                                                                                                                                                                                                                    
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Returns true if the client has a currently open socket.                                                                                                                                                                                                               
     * <p>                                                                                                                                                                                                                                                                   
     * @return True if the client has a curerntly open socket, false otherwise.                                                                                                                                                                                              
     ***/                                                                                                                                                                                                                                                                    
    public boolean isOpen()                                                                                                                                                                                                                                                  
    {                                                                                                                                                                                                                                                                        
        return _isOpen_;                                                                                                                                                                                                                                                     
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Set the default timeout in milliseconds to use when opening a socket.                                                                                                                                                                                                 
     * After a call to open, the timeout for the socket is set using this value.                                                                                                                                                                                             
     * This method should be used prior to a call to {@link #open open()}                                                                                                                                                                                                    
     * and should not be confused with {@link #setSoTimeout setSoTimeout()}                                                                                                                                                                                                  
     * which operates on the currently open socket.  _timeout_ contains                                                                                                                                                                                                      
     * the new timeout value.                                                                                                                                                                                                                                                
     * <p>                                                                                                                                                                                                                                                                   
     * @param timeout  The timeout in milliseconds to use for the datagram socket                                                                                                                                                                                            
     *                 connection.                                                                                                                                                                                                                                           
     ***/                                                                                                                                                                                                                                                                    
    public void setDefaultTimeout(int timeout)                                                                                                                                                                                                                               
    {                                                                                                                                                                                                                                                                        
        _timeout_ = timeout;                                                                                                                                                                                                                                                 
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Returns the default timeout in milliseconds that is used when                                                                                                                                                                                                         
     * opening a socket.                                                                                                                                                                                                                                                     
     * <p>                                                                                                                                                                                                                                                                   
     * @return The default timeout in milliseconds that is used when                                                                                                                                                                                                         
     *         opening a socket.                                                                                                                                                                                                                                             
     ***/                                                                                                                                                                                                                                                                    
    public int getDefaultTimeout()                                                                                                                                                                                                                                           
    {                                                                                                                                                                                                                                                                        
        return _timeout_;                                                                                                                                                                                                                                                    
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Set the timeout in milliseconds of a currently open connection.                                                                                                                                                                                                       
     * Only call this method after a connection has been opened                                                                                                                                                                                                              
     * by {@link #open open()}.                                                                                                                                                                                                                                              
     * <p>                                                                                                                                                                                                                                                                   
     * @param timeout  The timeout in milliseconds to use for the currently                                                                                                                                                                                                  
     *                 open datagram socket connection.                                                                                                                                                                                                                      
     ***/                                                                                                                                                                                                                                                                    
    public void setSoTimeout(int timeout) throws SocketException                                                                                                                                                                                                             
    {                                                                                                                                                                                                                                                                        
        _socket_.setSoTimeout(timeout);                                                                                                                                                                                                                                      
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Returns the timeout in milliseconds of the currently opened socket.                                                                                                                                                                                                   
     * If you call this method when the client socket is not open,                                                                                                                                                                                                           
     * a NullPointerException is thrown.                                                                                                                                                                                                                                     
     * <p>                                                                                                                                                                                                                                                                   
     * @return The timeout in milliseconds of the currently opened socket.                                                                                                                                                                                                   
     ***/                                                                                                                                                                                                                                                                    
    public int getSoTimeout() throws SocketException                                                                                                                                                                                                                         
    {                                                                                                                                                                                                                                                                        
        return _socket_.getSoTimeout();                                                                                                                                                                                                                                      
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Returns the port number of the open socket on the local host used                                                                                                                                                                                                     
     * for the connection.  If you call this method when the client socket                                                                                                                                                                                                   
     * is not open, a NullPointerException is thrown.                                                                                                                                                                                                                        
     * <p>                                                                                                                                                                                                                                                                   
     * @return The port number of the open socket on the local host used                                                                                                                                                                                                     
     *         for the connection.                                                                                                                                                                                                                                           
     ***/                                                                                                                                                                                                                                                                    
    public int getLocalPort()                                                                                                                                                                                                                                                
    {                                                                                                                                                                                                                                                                        
        return _socket_.getLocalPort();                                                                                                                                                                                                                                      
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Returns the local address to which the client's socket is bound.                                                                                                                                                                                                      
     * If you call this method when the client socket is not open, a                                                                                                                                                                                                         
     * NullPointerException is thrown.                                                                                                                                                                                                                                       
     * <p>                                                                                                                                                                                                                                                                   
     * @return The local address to which the client's socket is bound.                                                                                                                                                                                                      
     ***/                                                                                                                                                                                                                                                                    
    public InetAddress getLocalAddress()                                                                                                                                                                                                                                     
    {                                                                                                                                                                                                                                                                        
        return _socket_.getLocalAddress();                                                                                                                                                                                                                                   
    }                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                             
    /***                                                                                                                                                                                                                                                                     
     * Sets the DatagramSocketFactory used by the DatagramSocketClient                                                                                                                                                                                                       
     * to open DatagramSockets.  If the factory value is null, then a default                                                                                                                                                                                                
     * factory is used (only do this to reset the factory after having                                                                                                                                                                                                       
     * previously altered it).                                                                                                                                                                                                                                               
     * <p>                                                                                                                                                                                                                                                                   
     * @param factory  The new DatagramSocketFactory the DatagramSocketClient                                                                                                                                                                                                
     * should use.                                                                                                                                                                                                                                                           
     ***/                                                                                                                                                                                                                                                                    
    public void setDatagramSocketFactory(DatagramSocketFactory factory)                                                                                                                                                                                                      
    {                                                                                                                                                                                                                                                                        
        if (factory == null)                                                                                                                                                                                                                                                 
            _socketFactory_ = __DEFAULT_SOCKET_FACTORY;                                                                                                                                                                                                                      
        else                                                                                                                                                                                                                                                                 
            _socketFactory_ = factory;                                                                                                                                                                                                                                       
    }                                                                                                                                                                                                                                                                        
}                                                                                                                                                                                                                                                                            
